package control;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;

import util.Constants;
import view.ComponentWindow;
import view.MainWindow;
import view.VariableWindow;
import view.component.basecomponent.pojo.ComponentPojo;

import communication.MainCOMM;
import component.auxiliares.Campo;
import component.auxiliares.Progress;

import dao.IActionDAO;
import dao.IComponentDAO;
import dao.IPanelDAO;
import dao.IProjectDAO;
import dao.IVariableDAO;
import dao.impl.ActionDAO;
import dao.impl.ComponentDAO;
import dao.impl.PanelDAO;
import dao.impl.ProjectDAO;
import dao.impl.VariableDAO;
import entities.Action;
import entities.Panel;
import entities.Project;
import entities.Variable;

public class Supervisorio {

	private IProjectDAO projectDao;
	private IPanelDAO panelDao;
	private IComponentDAO componentDao;
	private IVariableDAO variableDao;
	private IActionDAO actionDao;

	private Project project;
	private Panel panel;
	private ComponentPojo component;
	private ArrayList<Variable> variables;

	private MainWindow mainWindow;
	private ComponentWindow componentWindow;
	private VariableWindow variableWindow;

	private MainCOMM mainComm;

	private boolean isSimulationRunning;

	private static Supervisorio myInstance;

	public static synchronized Supervisorio getInstance() {
		if (myInstance == null) {
			myInstance = new Supervisorio();
		}
		return myInstance;
	}

	public Project getProject() {
		return project;
	}

	public void setProject(Project project) {
		this.project = project;
	}

	public MainWindow getMainWindow() {
		return mainWindow;
	}

	public void setMainWindow(MainWindow mainWindow) {
		this.mainWindow = mainWindow;
	}

	public Panel createPanel(String name) {

		panel = new Panel();
		panel.setName(name);

		Collection<ComponentPojo> components = new ArrayList<ComponentPojo>();
		panel.setComponents(components);

		panelDao = new PanelDAO();
		projectDao = new ProjectDAO();
		panelDao.init();

		project = projectDao.getBy(project.getId());

		boolean status = panelDao.create(panel);

		project.getPanels().add(panel);

		projectDao.update(project);

		if (status)
			return panel;
		else
			return null;

	}

	public ArrayList<Variable> getAllVariables() {

		ArrayList<Variable> variables = new ArrayList<Variable>();

		for (Panel pnl : project.getPanels()) {
			for (ComponentPojo comp : pnl.getComponents()) {

				variables.addAll(comp.getVariables());
			}
		}

		return variables;

	}

	public void createProject(String nomeProjeto, String nomeFabrica,
			String descricao) {

		project = new Project();
		project.setName(nomeProjeto);
		project.setFactoryName(nomeFabrica);
		project.setDescription(descricao);

		Collection<Panel> panels = new ArrayList<Panel>();
		project.setPanels(panels);

		boolean status = false;

		projectDao = new ProjectDAO();
		projectDao.init();
		status = projectDao.create(project);

		if (status)
			mainWindow.enableAll();
		else
			JOptionPane.showMessageDialog(null, "Não criou o projeto");

	}

	public ComponentPojo createComponent(String name, int x, int y, Panel panel) {

		component = new ComponentPojo();
		component.setName(name);
		component.setX(x);
		component.setY(y);

		Collection<Variable> variables = new ArrayList<Variable>();
		component.setVariables(variables);

		componentDao = new ComponentDAO();
		panelDao = new PanelDAO();
		componentDao.init();

		panel = panelDao.getBy(panel.getId());

		componentDao.create(component);
		panel.getComponents().add(component);

		panelDao.update(panel);

		return component;

	}

	public ComponentPojo updateComponent(ComponentPojo pojo, String name,
			String description) {

		componentDao = new ComponentDAO();
		componentDao.init();

		component = componentDao.getBy(pojo.getId());

		component.setName(name);
		component.setDescription(description);

		boolean status = componentDao.update(component);

		if (status)
			return component;
		else
			return null;

	}

	public boolean createOrUpdateVariable(Variable variable,
			ComponentPojo pojo, String name, String address,
			String controllerAddress, String description, String equation) {

		boolean status = false;

		variableDao = new VariableDAO();
		variableDao.init();

		Variable v = variableDao.getBy(variable.getId());

		if (v != null) {
			System.out.println("variável já existente");

			v.setName(name);
			v.setDescription(description);
			v.setEquation(equation);
			v.setAddress((char) Integer.parseInt(address));
			v.setControllerAddress((char) Integer.parseInt(controllerAddress));

			status = variableDao.update(v);
		} else {
			System.out.println("nova variável");
			this.remoteVariableBuildTree();
			componentDao = new ComponentDAO();

			variable.setName(name);
			variable.setDescription(description);
			variable.setEquation(equation);
			variable.setAddress((char) Integer.parseInt(address));
			variable.setControllerAddress((char) Integer
					.parseInt(controllerAddress));

			Collection<Action> actions = new ArrayList<Action>();
			variable.setActions(actions);

			status = variableDao.create(variable);

			ComponentPojo compPojo = componentDao.getBy(pojo.getId());
			compPojo.getVariables().add(variable);

			componentDao.update(compPojo);

		}

		return status;
	}

	public void doOnClose() {

		if (projectDao == null)
			projectDao = new ProjectDAO();

		projectDao.close();

	}

	public ComponentWindow getComponentWindow() {
		return componentWindow;
	}

	public void setComponentWindow(ComponentWindow componentWindow) {
		this.componentWindow = componentWindow;
	}

	public VariableWindow getVariableWindow() {
		return variableWindow;
	}

	public void setVariableWindow(VariableWindow variableWindow) {
		this.variableWindow = variableWindow;
	}

	public void updateComponentVariables() {
		this.componentWindow.updateVariablesTbl();

	}

	public void deleteComponent(ComponentPojo pojo) {
		componentDao = new ComponentDAO();
		panelDao = new PanelDAO();
		componentDao.init();

		for (Panel panel : panelDao.getAll()) {
			if (panel.getComponents().contains(pojo)) {
				panel.getComponents().remove(pojo);
				break;
			}
		}

		panelDao.update(panel);
		componentDao.delete(pojo);
	}

	public void deleteVariable(Variable variable) {
		componentDao = new ComponentDAO();
		variableDao = new VariableDAO();

		variableDao.init();

		for (ComponentPojo comp : componentDao.getAll()) {
			if (comp.getVariables().contains(variable)) {
				comp.getVariables().remove(variable);
				break;
			}
		}

		componentDao.update(component);
		variableDao.delete(variable);

	}

	public void createAction(Variable currentVariable, String name,
			double reference, int actionType, String result, String operation) {

		Action action = new Action();
		action.setName(name);
		action.setReference(reference);
		action.setResult(result);
		action.setActionType(actionType);
		action.setOperation(operation);

		actionDao = new ActionDAO();
		variableDao = new VariableDAO();

		actionDao.init();

		Variable v = variableDao.getBy(currentVariable.getId());

		actionDao.create(action);

		v.getActions().add(action);
		variableDao.update(v);

		variableWindow.updateActionsTbl();

	}

	public void stopCommunication() {
		this.isSimulationRunning = false;
		mainComm.stopCommunication();
	}

	public void initiateCommunication() {
		variables = this.getAllVariables();
		this.isSimulationRunning = true;
		mainComm = new MainCOMM();
		mainComm.initiateCommunication(variables);
		Thread t = new Thread(new Runnable() {
			public void run() {
				while (isSimulationRunning) {
					boolean k = mainComm.isBusyFlag();
					while (k) {
					}
					mainComm.setFree(false);
					populateTable(variables);

					for (Object obj : mainWindow.getAuxiliares()) {

						if (obj instanceof Campo) {
							Campo c = (Campo) obj;
							c.atualiza();
						} else if (obj instanceof Progress) {
							Progress p = (Progress) obj;
							p.atualiza();
						}
					}

					mainComm.setFree(true);
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
		// disparar a Thread
		t.start();

	}

	protected void populateTable(ArrayList<Variable> vs) {

		String[][] rows = new String[vs.size()][2];
		for (int i = 0; i < vs.size(); i++) {
			Variable variable = vs.get(i);
			rows[i][0] = variable.getName();
			rows[i][1] = String.valueOf(this.manipulatedValue(variable));

			for (Action action : variable.getActions()) {
				this.manipulateAction(variables.get(i), action);
			}

		}

		mainWindow.updateVariableTbl(rows);
	}

	public void manipulateAction(Variable variable, Action action) {

		String operation = action.getOperation();

		double value = (double) variable.getValue();

		if (operation.equals("maior que")) {
			if (value > action.getReference())
				this.doActionType(variable, action);
		} else if (operation.equals("menor que")) {
			if (value < action.getReference())
				this.doActionType(variable, action);
		} else if (operation.equals("diferente de")) {
			if (value != action.getReference())
				this.doActionType(variable, action);
		} else if (operation.equals("igual a")) {
			if (value == action.getReference())
				this.doActionType(variable, action);
		}

	}

	private void doActionType(Variable variable, Action action) {

		switch (action.getActionType()) {
		case Constants.ACTION_SHOW_MESSAGE:
			JOptionPane.showMessageDialog(null, action.getResult(),
					"Variável: " + variable.getName(), 0);
			break;

		case Constants.ACTION_SAVE_LOG:
			this.persistLog(variable, action);
			break;

		case Constants.ACTION_SEND_VARIABLE_VALUE:
			break;

		}

	}

	private void persistLog(Variable variable, Action action) {
		System.out.println("Persistiu:");
		System.out.println("  Variável: " + variable.getName());
		System.out.println("  Mensagem: " + action.getResult());
		System.out.println("  Hora: " + new Date().toLocaleString());

	}

	private double manipulatedValue(Variable variable) {

		String equation = variable.getEquation();

		char[] charArray = equation.toCharArray();

		double result = (int) variable.getValue();

		String temp = "";

		for (int i = 0; i < charArray.length; i++) {

			if (charArray[i] == '+') {
				temp = equation.substring(i + 1);
				result = result
						+ Integer
								.parseInt(temp.substring(0, temp.indexOf(")")));
			} else if (charArray[i] == '-') {
				temp = equation.substring(i + 1);
				result = result
						- Integer
								.parseInt(temp.substring(0, temp.indexOf(")")));
			} else if (charArray[i] == '*') {
				temp = equation.substring(i + 1);
				result = result
						* Integer
								.parseInt(temp.substring(0, temp.indexOf(")")));
			} else if (charArray[i] == '/') {
				System.out.println(i);
				System.out.println(equation);
				temp = equation.substring(i + 1);
				result = result
						/ Integer
								.parseInt(temp.substring(0, temp.indexOf(")")));
			}

		}

		return result;
	}

	public boolean isSimulationRunning() {
		return isSimulationRunning;
	}

	public void setSimulationRunning(boolean isSimulationRunning) {
		this.isSimulationRunning = isSimulationRunning;
	}

	public void showVariablesOf(ComponentPojo pojo) {
		this.variables = new ArrayList<Variable>(pojo.getVariables());
		this.mainWindow.getTblVariaveis().setModel(new DefaultTableModel());

	}

	public ArrayList<Variable> getVariables() {
		return variables;
	}

	public void setVariables(ArrayList<Variable> variables) {
		this.variables = variables;
	}

	public void remoteVariableBuildTree() {
		mainWindow.buildTree();
	}

	public DefaultMutableTreeNode buildTree() {
		DefaultMutableTreeNode projectNode = new DefaultMutableTreeNode(
				this.project.getName());
		List<Panel> panels = new ArrayList<Panel>(this.project.getPanels());

		for (int i = 0; i < panels.size(); i++) {
			Panel currentPanel = panels.get(i);
			DefaultMutableTreeNode panelNode = new DefaultMutableTreeNode(
					currentPanel.getName());
			projectNode.add(panelNode);
			List<ComponentPojo> components = new ArrayList<ComponentPojo>(
					currentPanel.getComponents());

			for (int j = 0; j < components.size(); j++) {
				ComponentPojo currentComponent = components.get(j);
				DefaultMutableTreeNode componentNode = new DefaultMutableTreeNode(
						currentComponent.getName());
				panelNode.add(componentNode);
				List<Variable> variables = new ArrayList<Variable>(
						currentComponent.getVariables());

				for (int k = 0; k < variables.size(); k++) {
					DefaultMutableTreeNode variableNode = new DefaultMutableTreeNode(
							variables.get(k).getName());
					componentNode.add(variableNode);
				}
			}
		}
		return projectNode;
	}
}
